﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using ICSharpCode.WinFormsUI.Controls.Chart;

namespace ICSharpCode.WinFormsUI.Controls.Chart3D
{
    public partial class NChart3DControl : UserControl
    {
        int dragPointX = 0;
        int dragPointY = 0;
        bool dragging = false;       

        ViewPort viewPort = null;

        private ChartEventHandler shapeClick = null;
        public ChartEventHandler ShapeClick
        {
            get { return shapeClick; }
            set { shapeClick = value; }
        }

        private RotateStyle _rotateStyle = RotateStyle.X;
        public RotateStyle RotateStyle
        {
            get { return _rotateStyle; }
            set { _rotateStyle = value; }
        }

        private bool _showCursorValue;
        public bool ShowCursorValue
        {
            get { return _showCursorValue; }
            set { _showCursorValue = value; }
        }

        private string _cursorValueFormat = "({0},{1},{2})";
        public string CursorValueFormat
        {
            get { return _cursorValueFormat; }
            set { _cursorValueFormat = value; }
        }

        private bool _invalidateable = true;
        internal bool Invalidateable
        {
            get { return _invalidateable; }
        }

        public ViewPort ViewPort
        {
            get { return viewPort; }
        }

        public GraphicShapes3D GraphicShapes
        {
            get { return viewPort.GraphicShapes; }
        }

        public NChart3DControl()
        {
            InitializeChart();
            InitializeComponent();            
        }

        private void InitializeChart()
        {
            viewPort = new ViewPort(this);
            shapeClick = new ChartEventHandler(this);
            this.SetStyle(ControlStyles.ResizeRedraw |
              ControlStyles.OptimizedDoubleBuffer |
              ControlStyles.AllPaintingInWmPaint, true);
            this.UpdateStyles();  
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);         
            viewPort.Render(e.Graphics);     
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (e.Button == MouseButtons.Left)
            {
                dragging = true;
                dragPointX = e.X;
                dragPointY = e.Y;               
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (dragging)
            {
                switch (_rotateStyle)
                {
                    case RotateStyle.X:
                        viewPort.RotateX(e.X - dragPointX);
                        break;
                    case RotateStyle.Y:
                        viewPort.RotateY(e.Y - dragPointY);
                        break;
                    case RotateStyle.XY:
                        viewPort.Rotate((e.Y - dragPointY), (e.X - dragPointX));
                        break;
                }               
            }
            else if (_showCursorValue)
            {
                Shape3D shape = null;
                Point3D pt3d = viewPort.GraphicShapes.FindNestPoint(e.Location, out shape);
                viewPort.GraphicShapes.SetCursorPoint3d(shape, pt3d);                 
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);
            if (e.Button == MouseButtons.Left)
            {
                dragging = false;
            }

            if (ShapeClick != null && ShapeClick.eventHandler != null)
            {
                Shape3D shape = null;
                Point3D pt3d = viewPort.GraphicShapes.FindNestPoint(e.Location, out shape);
                if (shape != null && pt3d != null)
                {
                    ShapeClick.eventHandler(this, new ChartEventArgs(shape) { Tag = pt3d });
                }
            }

        }

        public void SetLookAt(int x, int y, int z)
        {
            this.viewPort.SetLookAt(x, y, z);
        }

        public void BeginUpdate()
        {
            _invalidateable = false;
        }

        public void EndUpdate()
        {
            _invalidateable = true;
            this.Invalidate();
        }

    }

    public enum RotateStyle{
        X,
        Y,
        XY
    }
}
